package com.socialin.picsin.camera.view;

import java.util.List;

import android.content.Context;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.media.AudioManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.ViewGroup.LayoutParams;

public class CameraViewCupcake extends SurfaceView implements ICamera, Callback {
	public static final String	TAG				= "CameraView";

	protected Camera			camera;
	protected SurfaceHolder		surfaceHolder;
	protected Parameters		params;

	protected int				previewWidth	= 800;
	protected int				previewHeight	= 480;
	protected boolean			canTakePic		= false;

	protected Callback			surfaceCreatedCallback;

	protected int				minBrightness	= Integer.MIN_VALUE;
	protected int				maxBrightness	= Integer.MIN_VALUE;

	protected int				minContrast		= Integer.MIN_VALUE;
	protected int				maxContrast		= Integer.MIN_VALUE;
	protected int				minSaturation	= Integer.MIN_VALUE;
	protected int				maxSaturation	= Integer.MIN_VALUE;
	protected int				minSharpness	= Integer.MIN_VALUE;
	protected int				maxSharpness	= Integer.MIN_VALUE;
	public boolean				isPicTaking		= false;

	protected String			defProperties;
	protected String propertiesForSending;
	
	protected boolean isReleased = false;
	
	protected boolean previewRunning = false;
	
	protected String isoKey = null;
	
	protected boolean isPlayShutter = true;
	
//	public static int					maxWidth							= 1024;
//	public static int					maxHeight							= 768;
//	public static final int minWidth = 640;
//	public static final int minHeight = 480;
//	static {
//		int memory = (int) (Runtime.getRuntime().maxMemory() / 1024 / 1024);
//		if (memory < 24) {
//			maxWidth = (int) (maxWidth / 1.6f);
//			maxHeight = (int) (maxHeight / 1.6f);
//		}
//	}
	
	protected int maxWidth;
	protected int maxHeight;

	public CameraViewCupcake(Context context, LayoutParams layoutParams) {
		super(context);
		setLayoutParams(layoutParams);
		init();
	}

	public CameraViewCupcake(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	protected void init() {
		surfaceHolder = getHolder();
		surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		surfaceHolder.addCallback(this);
	}
	
	protected void sendParams(final Exception e) {
		boolean isSend = getContext().getSharedPreferences("CameraView", getContext().MODE_PRIVATE).getBoolean("is.send", false);
		if(isSend)
			return;
//		new Thread(){
//			@Override
//			public void run() {
//				DefaultHttpClient httpClient = new DefaultHttpClient();
//				PackageManager pm = getContext().getPackageManager();
//				PackageInfo pi;
//				final Writer result = new StringWriter();
//			    final PrintWriter printWriter = new PrintWriter(result);
//			    e.printStackTrace(printWriter);
//				try {
//					pi = pm.getPackageInfo(getContext().getPackageName(), 0);
//					HttpPost httpPost = new HttpPost("http://socialin.com/services/exception.php");
//					List<NameValuePair> nvps = new ArrayList<NameValuePair>();
//					nvps.add(new BasicNameValuePair(Constants.SECURITY_TOKEN, "SocialInGames2011"));
//					nvps.add(new BasicNameValuePair(Constants.APPLICATION_VERSION, pi.versionName + "_camera"));
//					nvps.add(new BasicNameValuePair(Constants.APPLICATION_PACKAGE, pi.packageName));
//					nvps.add(new BasicNameValuePair(Constants.PHONE_MODEL, android.os.Build.MODEL));
//					nvps.add(new BasicNameValuePair(Constants.ANDROID_VERSION, android.os.Build.VERSION.RELEASE));
//					nvps.add(new BasicNameValuePair(Constants.APPLICATION_STACKTRACE, result.toString()));
//					nvps.add(new BasicNameValuePair(Constants.ADDITIONAL_DATA, propertiesForSending));
//					httpPost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
//					httpClient.execute(httpPost);
//					getContext().getSharedPreferences("CameraView", getContext().MODE_PRIVATE).edit().putBoolean("is.send", true).commit();
//				} catch (UnsupportedEncodingException e) {
//					e.printStackTrace();
//				} catch (ClientProtocolException e) {
//					e.printStackTrace();
//				} catch (IOException e) {
//					e.printStackTrace();
//				} catch (NameNotFoundException e1) {
//					e1.printStackTrace();
//				}catch (Exception e) {
//					e.printStackTrace();
//				}
//			}
//		}.start();
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		// camera.setDisplayOrientation(90);//only 2.2>
		try {
			camera = Camera.open();
			camera.setPreviewDisplay(surfaceHolder);
		} catch (Exception e) {
			e.printStackTrace();
			surfaceCreatedCallback.surfaceCreated(null);
			return;
		}
		surfaceCreatedCallback.surfaceCreated(holder);
	}
	
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
		try {
			if (previewRunning) {
				camera.startPreview();
			}
		} catch (Exception e) {
		}
		
		
		if(camera == null){
			surfaceCreatedCallback.surfaceChanged(null, -1, -1, -1);
			return;
		}
		
		if (params == null) {
			params = camera.getParameters();
			// params.set("orientation", "landscape");
			params.setPictureFormat(PixelFormat.JPEG);
		}
		// params.setPreviewSize(previewWidth, previewHeight);
		propertiesForSending = params.flatten();
		if(defProperties == null){
			defProperties = propertiesForSending.replace(" ", "");
			params.unflatten(defProperties);
			Log.d(TAG, defProperties);
		}
		try{
		   camera.setParameters(params);
		}catch(Exception e){
			sendParams(e);
			 try {
                 defProperties = params.flatten();
                 params.unflatten(defProperties);
                 camera.setParameters(params);
              }catch (Exception e1) {
            	  sendParams(e);
             }
		}
		
		try {
			//camera.startPreview();
			//previewRunning = true;
			isReleased = false;
		}catch (Exception e) {		
			previewRunning = false;
			surfaceCreatedCallback.surfaceChanged(null, -1, -1, -1);
			return;
		}
		
		brightnessSupported();
		contrastSupported();
		saturationSupported();
		sharpnessSupported();
		canTakePic = true;
		surfaceCreatedCallback.surfaceChanged(holder, format, width, height);
//		initCameraSize();  
	}

	/*protected void initCameraSize() {
		try {
			String[] sizesString = getPictureSizeValues();
			if (sizesString == null || sizesString.length == 1) return;
			int bestWidth = 1024;
			int bestSupportedWidth = Integer.MAX_VALUE;
			int bestSupportedHeight = Integer.MAX_VALUE;
			int maxWidth = Integer.MIN_VALUE;
			int h = Integer.MIN_VALUE;
			for (int i = 0; i < sizesString.length; i++) {
				String curStr = sizesString[i];
				int width = Integer.parseInt((String) curStr.subSequence(0, curStr.indexOf("x")));
				int height = Integer.parseInt((String) curStr.subSequence(curStr.indexOf("x") + 1, curStr.length()));
				if (width > maxWidth) {
					maxWidth = width;
					h = height;
				}
				if (width == bestWidth) {
					bestSupportedWidth = bestWidth;
					bestSupportedHeight = height;
					break;
				} else if (width > bestWidth && bestSupportedWidth > width) {
					bestSupportedWidth = width;
					bestSupportedHeight = height;
				}
			}
			if (bestSupportedWidth == Integer.MAX_VALUE) {
				bestSupportedWidth = maxWidth;
				bestSupportedHeight = h;
			}
			params.setPictureSize(bestSupportedWidth, bestSupportedHeight);
		} catch (Exception e) {
			//no op
		} 
	}*/

	@Override
	public String getDefaultProperties() {
		return defProperties;
	}  

	@Override
	public void setDefaultProperties() {
		params.unflatten(defProperties);
		camera.setParameters(params);
	}

	public String getProperties() {
		return params.flatten();
	}

	public void setProperties(String props) {
		params.unflatten(props);
		camera.setParameters(params);
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		if(camera == null){
			surfaceCreatedCallback.surfaceDestroyed(null);
			return;
		}
		try {
			camera.stopPreview();
			camera.release();
			camera = null;
		}catch (Exception e) {
			// no op
		}
		isReleased = true;
		surfaceCreatedCallback.surfaceDestroyed(holder);
	}

	public void setSurfaceChangeCallback(Callback callback) {
		surfaceCreatedCallback = callback;
	}

	public void takePicture(final ShutterCallback shutter, final PictureCallback raw, final PictureCallback jpeg) {
		if(camera == null)
			return;
		try{
			camera.setParameters(params);
		}catch (Exception e) {
			// no op
		}
		if (canTakePic && !isPicTaking) {
			isPicTaking = true;
			camera.autoFocus(new AutoFocusCallback() {

				@Override
				public void onAutoFocus(boolean success, Camera camera) {
					AudioManager mgr = (AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE);
				    mgr.setStreamMute(AudioManager.STREAM_SYSTEM, true);
					if(!isReleased)
						camera.takePicture(shutter, raw, jpeg);
				}
			});
		}
	}

	@Override
	public Camera getCamera() {
		return camera;
	}

	@Override
	public boolean commit() {
		try {
			camera.setParameters(params);
			return true;
		} catch (Exception e) {
			sendParams(e);
			return false;
		}
		
	}

	@Override
	public void setBrightness(int value) {
		params.set("brightness", value);
	}

	@Override
	public int getBrightness() {
		return params.getInt("brightness");
	}

	@Override
	public boolean brightnessSupported() {
		try {
			if (params.get("brightness") != null) {
				minBrightness = 0;
				if (params.get("brightness-min") != null) {
					minBrightness = params.getInt("brightness-min");
				}
				if (params.get("brightness-max") != null) {
					maxBrightness = params.getInt("brightness-max");
				} else if (maxBrightness == Integer.MIN_VALUE) {
					maxBrightness = 2 * params.getInt("brightness");
				}
				if (minBrightness == maxBrightness) return false;
				if (minBrightness > maxBrightness) {
					int t = minBrightness;
					minBrightness = maxBrightness;
					maxBrightness = t;
				}
				return true;
			}
			return false;
		} catch (Exception e) {
			return false;
		}
	}

	@Override
	public int getMinBrightness() {
		return minBrightness;
	}

	@Override
	public int getMaxBrightness() {
		return maxBrightness;
	}

	@Override
	public int getMinContrast() {
		return minContrast;
	}

	@Override
	public int getMaxContrast() {
		return maxContrast;
	}

	@Override
	public boolean contrastSupported() {
		try {
			if (params.get("contrast") != null) {
				minContrast = 0;
				if (params.get("contrast-min") != null) {
					minContrast = params.getInt("contrast-min");
				}else if (params.get("min-contrast") != null) {
					minContrast = params.getInt("min-contrast");
				}
				if (params.get("contrast-max") != null) {
					maxContrast = params.getInt("contrast-max");
				} else if (params.get("max-contrast") != null) {
					maxContrast = params.getInt("max-contrast");
				} else if (maxContrast == Integer.MIN_VALUE) {
					maxContrast = 2 * params.getInt("contrast");
					// Log.d(TAG, "max contrast: " + maxContrast);
				}
				if (minContrast == maxContrast) return false;
				if (minContrast > maxContrast) {
					int t = minContrast;
					minContrast = maxContrast;
					maxContrast = t;
				}
				return true;
			}
			return false;
		} catch (Exception e) {
			return false;
		}
	}

	@Override
	public void setContrast(int value) {
		params.set("contrast", value);
	}

	@Override
	public int getContrast() {
		return params.getInt("contrast");
	}

	@Override
	public int getMinSharpness() {
		return minSharpness;
	}

	@Override
	public int getMaxSharpness() {
		return maxSharpness;
	}

	@Override
	public boolean sharpnessSupported() {
		try {
			if (params.get("sharpness") != null) {
				minSharpness = 0;
				if (params.get("sharpness-min") != null) {
					minSharpness = params.getInt("sharpness-min");
				}else if(params.get("min-sharpness") != null){
					minSharpness = params.getInt("min-sharpness");
				}
				if (params.get("sharpness-max") != null) {
					maxSharpness = params.getInt("sharpness-max");
				} else if (params.get("max-sharpness") != null) {
					maxSharpness = params.getInt("max-sharpness");
				} else if (maxSharpness == Integer.MIN_VALUE) {
					maxSharpness = 2 * params.getInt("sharpness");
				}
				if (minSharpness == maxSharpness) return false;
				if (minSharpness > maxSharpness) {
					int t = minSharpness;
					minSharpness = maxSharpness;
					maxSharpness = t;
				}
				return true;
			}

			return false;
		}catch (Exception e) {
			return false;
		}
	}

	@Override
	public void setSharpness(int value) {
		params.set("sharpness", value);
	}

	@Override
	public int getSharpness() {
		return params.getInt("sharpness");
	}

	@Override
	public int getMinSaturation() {
		return minSaturation;
	}

	@Override
	public int getMaxSaturation() {
		return maxSaturation;
	}

	@Override
	public boolean saturationSupported() {
		try{
			if (params.get("saturation") != null) {
				minSaturation = 0;
				if (params.get("saturation-min") != null) {
					minSaturation = params.getInt("saturation-min");
				} else if (params.get("min-saturation") != null) {
					minSaturation = params.getInt("min-saturation");
				} else {
					minSaturation = 0;
				}
				if (params.get("saturation-max") != null) {
					maxSaturation = params.getInt("saturation-max");
				} else if (params.get("max-saturation") != null) {
					maxSaturation = params.getInt("max-saturation");
				} else if (maxSaturation == Integer.MIN_VALUE) {
					maxSaturation = 2 * params.getInt("saturation");
				}
				if (minSaturation == maxSaturation) return false;
				if (minSaturation > maxSaturation) {
					int t = minSaturation;
					minSaturation = maxSaturation;
					maxSaturation = t;
				}
				return true;
			}
			return false;
		}catch (Exception e) {
			return false;
		}
	}

	@Override
	public void setSaturation(int value) {
		params.set("saturation", value);
	}

	@Override
	public int getSaturation() {
		return params.getInt("saturation");
	}

	@Override
	public String[] getWhiteBalanceValues() {
		String values = params.get("whitebalance-values");
		if (values != null) { return params.get("whitebalance-values").split(","); }

		return null;
	}

	@Override
	public void setWhiteBalance(String value) {
		params.set("whitebalance", value);
	}

	@Override
	public String getWhiteBalance() {
		return params.get("whitebalance");
	}

	@Override
	public String[] getEffects() {
		String values = params.get("effect-values");
		if (values != null) return params.get("effect-values").split(",");
		return null;
	}

	@Override
	public void setEffect(String value) {
		params.set("effect", value);
	}

	@Override
	public String getEffect() {
		return params.get("effect");
	}

	@Override
	public String[] getSceneModeValues() {
		String values = params.get("scene-mode-values");
		if (values != null) return params.get("scene-mode-values").split(",");
		return null;
	}

	@Override
	public void setSceneMode(String value) {
		params.set("scene-mode", value);
	}

	@Override
	public String getSceneMode() {
		return params.get("scene-mode");
	}

	@Override
	public String[] getIsoValues() {
		final String[] keyForIso = {"iso", "picture-iso", "mot-picture-iso", "nv-picture-iso"};
		for(int i = 0; i < keyForIso.length; i++){
			String cur = keyForIso[i];
			if(params.get(cur) != null){
				isoKey = cur;
				break;
			}
		}
		final String[] keys = {"iso-values", "picture-iso-values", "mot-picture-iso-values", "nv-picture-iso-values"};
		String result[] = null;
		for(int i = 0; i < keys.length; i++){
			String cur = keys[i];
			if(params.get(cur) != null)
				result = params.get(cur).split(",");
		}
		if(isoKey == null)
			result = null;
		if(result != null && result.length == 1)
			result = null;
		return result;
	}

	@Override
	public void setIso(String value) {
		params.set(isoKey, value);
	}

	@Override
	public String getIsoMode() {
		return params.get(isoKey);
	}

	@Override
	public int getFlashMode() {
		String flashMode = params.get("flash-mode");
		if (flashMode == null) return FLASH_MODE_INVALID;
		if (flashMode.equalsIgnoreCase("on")) return FLASH_MODE_ON;
		else if (flashMode.equalsIgnoreCase("off")) {
			return FLASH_MODE_OFF;
		} else if (flashMode.equalsIgnoreCase("auto")) { return FLASH_MODE_AUTO; }
		return FLASH_MODE_INVALID;
	}

	public void setFlashMode(int flashMode) {
		if (flashMode == FLASH_MODE_ON) params.set("flash-mode", "on");
		else if (flashMode == FLASH_MODE_OFF) {
			params.set("flash-mode", "off");
		} else if (flashMode == FLASH_MODE_AUTO) {
			params.set("flash-mode", "auto");
		}
	}

	@Override
	public int[] getFlashModeValues() {
		String values = params.get("flash-mode-values");
		if (values != null) {
			String[] flashModeValues = values.split(",");
			if(flashModeValues.length == 1)
				return null;
			int[] result = { FLASH_MODE_INVALID, FLASH_MODE_INVALID, FLASH_MODE_INVALID };
			for (int i = 0; i < flashModeValues.length; i++) {
				if ((flashModeValues[i]).equalsIgnoreCase("on")) {
					result[0] = FLASH_MODE_ON;
				} else if ((flashModeValues[i]).equalsIgnoreCase("off")) {
					result[1] = FLASH_MODE_OFF;
				} else if ((flashModeValues[i]).equalsIgnoreCase("auto")) {
					result[2] = FLASH_MODE_AUTO;
				}
			}
			return result;
		}
		return null;
	}

	public boolean isThreeFlashModesSupported() {
		int[] flashModes = getFlashModeValues();
		if (flashModes == null) return false;
		boolean isOnSupported = false;
		boolean isOffSupported = false;
		boolean isAutoSupported = false;
		for (int i = 0; i < flashModes.length; i++) {
			if (flashModes[i] == FLASH_MODE_AUTO) {
				isAutoSupported = true;
			} else if (flashModes[i] == FLASH_MODE_ON) {
				isOnSupported = true;
			} else if (flashModes[i] == FLASH_MODE_OFF) {
				isOffSupported = true;
			}
		}
		return (isOnSupported && isOffSupported && isAutoSupported);
	}

	@Override
	public String[] getFocusModeValues() {
		String values = params.get("focus-mode-values");
		if (values != null) {
			String[] result = params.get("focus-mode-values").split(",");
			return result;
		}
		return null;
	}

	@Override
	public void setFocusMode(String value) {
		params.set("focus-mode", value);
	}

	public String getFocusMode() {
		return params.get("focus-mode");
	}

	@Override
	public int getZoomMax() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public boolean zoomSupported() {
		return false;
	}

	@Override
	public boolean zoomSmoothSupported() {
		return false;
	}

	@Override
	public void setZoom(int value) {
	}
	
	@Override
	public int getZoom() {
		return 0;
	}

	@Override
	public List<Integer> getZoomFactors() {
		return null;
	}

	@Override
	public String[] getPictureSizeValues() {
		String values = params.get("picture-size-values");
		if (values != null) {
			String[] result = params.get("picture-size-values").split(",");
			return result;
		}
		return null;
	}

	@Override
	public String getPictureSize() {
		return params.get("picture-size");
	}

	@Override
	public void setPictureSize(int width, int height) {
		params.setPictureSize(width, height);
	}

	@Override
	public void setRotation(int value) {
		if (params.get("rotation") != null) {
			params.set("rotation", value);
		}
	}

	@Override
	public boolean getPictureTaking() {
		return isPicTaking;
	}

	@Override
	public void setPictureTaking(boolean value) {
		isPicTaking = value;
	}

	@Override
	public int getNumberOfCameras() {
		return 1;
	}

	@Override
	public void setCameraIndex(int index) {
		//no op
	}
	
	@Override
	public int getCameraIndex() {
		return 0;
	}

	@Override
	public void setPlayShutter(boolean pIsPlayShutter) {
		isPlayShutter = pIsPlayShutter;
	}

	@Override
	public boolean isPlayShutter() {
		return isPlayShutter;
	}

	@Override
	public void setImageSize(int width, int height) {
		maxWidth = width;
		maxHeight = height;
	}

	@Override
	public int getImageWidth() {
		return maxWidth;
	}

	@Override
	public int getImageHeight() {
		return maxHeight;
	}

	@Override
	public void releaseCamera() {
		if(camera != null)
			camera.release();
	}

	@Override
	public int getOrientation() {
		return 0;
	}

	@Override
	public void setOrientation(int val) {
		
	}

	
}
